package ll1;

import java.util.ArrayList;

public class LL1Driver {
	private boolean parseComplete;
	private ArrayList<String> stack;
	private String input;
	private LL1Table table;
	private int stackIndex;
	private String startToken;
	private String errLog;
	public LL1Driver(LL1Table aTable, String start){
		errLog = "";
		parseComplete = false;
		startToken = start;
		stackIndex = 0;
		table = aTable;
		stack = new ArrayList<String>();
		//Initalize stack
		push("$");
		LL1Node temp = table.lookUp(start);
		ArrayList<Token> list = temp.getOthers().get(0).getContent();
		for(int i = list.size() - 1; i > -1; i--){
			push(list.get(i).getName());
		}
	}
	
	public String parseInput(String input){
		ArrayList<String> list = convertToWords(input);
		String s = "";
		for(int i = 0; i < list.size();){
			String element = list.get(i);
			if(table.getTokens().contains(element)){	//if it is keyword
				
			}
			//element could be a variable input (might be ID, REGEX, or ASCII-STR)
			else if(element.charAt(0) == '\'' && element.charAt(element.length() - 1) == '\''){	//REGEX
				element = "REGEX";
			}
			else if(element.charAt(0) == '"'  && element.charAt(element.length() - 1) == '"'){	//defined by ASCII-STR
				element = "ASCII-STR";
			}
			else if(isID(element)){	//ID
				element = "ID";
			}
			
			if(element.equals(peek())){	//check if it is terminal/keyword
				s += pop() + " ";
				i++;					//advance input
			}
			else if(peek().charAt(0) == '<'){	//is a nonterminal coming next?
				String tempor = pop();
				s += tempor + " ";
				
				LL1Node temp = table.getRule(tempor, element);  //predict what rule to put into stack
				ArrayList<Token> ruleList = temp.getContent();
				for(int j = ruleList.size() - 1; j > -1; j--){
					if(!ruleList.get(j).getName().equals("epilson")){
						push(ruleList.get(j).getName());
					}
				}				
			}
			else{
				errLog += "PARSE ERROR on '" + list.get(i) + "'.\nPREDICTING: '" + peek() + "'\nCannot continue.\n\n";
				break;
			}
		}
		if(peek().equals("$")){
			parseComplete = true;
		}
		return s;
	}
	
	private ArrayList<String> convertToWords(String input){
		char[] letters = input.toCharArray();
		int index = 0;
		boolean done = false;
		String temp;
		ArrayList<String> inputList = new ArrayList<String>();
		while(!done){
			temp = "";
			while(!done && letters[index] != ' '){
				temp += letters[index];
				index++;
				if(index == letters.length){
					done = true;
				}
			}
			index++;
			if(!temp.isEmpty()){
				inputList.add(temp);
			}
			if(index == letters.length){
				done = true;
			}
		}
		return inputList;
	}
	
	private boolean isID(String input){ //checks to see if the string is defined as ID
		char[] inputChar = input.toCharArray();
		if(inputChar.length > 10){
			return false;	//cannot have a name that is more than 10 characters 
		}
		else{
			if((inputChar[0] > 64 && inputChar[0] < 91) || (inputChar[0] > 96 && inputChar[0] < 123)){	//first charcter must be a letter
				for(int i = 1; i < inputChar.length; i++){
					if((inputChar[0] > 64 && inputChar[0] < 91) || 			//upper case A-Z
							(inputChar[0] > 96 && inputChar[0] < 123) ||	//lower case a-Z
							(inputChar[0] > 47 && inputChar[0] < 58)  ||	//numbers 0-9
							(inputChar[0] == 95)){							//underscore _
						
					}
					else{
						return false;		//if other characters are found, not ID
					}
				}
			}
			else{
				return false;
			}
		}
		return true;
	}
	
	private void push(String stuff){
		stack.add(0, stuff);
		stackIndex++;
	}
	
	private String pop(){
		stackIndex--;
		return stack.remove(0);
	}
	
	private String peek(){
		return stack.get(0);
	}

	public boolean isParseComplete() {
		return parseComplete;
	}
	
	public String getErrorLog(){
		return errLog;
	}
}
